"""
Tool management system implementation
"""
from typing import Any, Callable, Dict, List, Optional, Type, Union, get_type_hints
import inspect
from functools import wraps
from pydantic import BaseModel, Field, create_model
from pydantic.fields import FieldInfo
import openai

def field(
    description: str = None,
    default: Any = ...,
    choices: List[Any] = None,
    examples: List[Any] = None,
    min_value: Optional[Union[int, float]] = None,
    max_value: Optional[Union[int, float]] = None,
    min_length: Optional[int] = None,
    max_length: Optional[int] = None,
    **kwargs
) -> Any:
    """
    创建工具参数字段
    Args:
        description: 参数描述
        default: 默认值
        choices: 可选值列表
        examples: 示例值列表
        min_value: 最小值（数字类型）
        max_value: 最大值（数字类型）
        min_length: 最小长度（字符串类型）
        max_length: 最大长度（字符串类型）
        **kwargs: 其他Field参数
    Returns:
        Field实例
    """
    field_kwargs = {}
    
    if description:
        field_kwargs['description'] = description
    if choices:
        if not isinstance(choices, (list, tuple, set)):
            raise ValueError("choices must be a sequence")
        field_kwargs['enum'] = list(choices)
    if examples:
        if not isinstance(examples, (list, tuple)):
            raise ValueError("examples must be a sequence")
        field_kwargs['examples'] = list(examples)
    if min_value is not None:
        field_kwargs['ge'] = min_value
    if max_value is not None:
        field_kwargs['le'] = max_value
    if min_length is not None:
        field_kwargs['min_length'] = min_length
    if max_length is not None:
        field_kwargs['max_length'] = max_length
        
    field_kwargs.update(kwargs)
    
    if default is ...:
        return Field(..., **field_kwargs)
    return Field(default, **field_kwargs)

def validate(field_name: str, **constraints):
    """
    为函数参数添加验证约束的装饰器
    Args:
        field_name: 参数名
        **constraints: 约束条件
    """
    def decorator(func):
        if not hasattr(func, '__field_constraints__'):
            func.__field_constraints__ = {}
        func.__field_constraints__[field_name] = constraints
        return func
    return decorator

class ToolInfo:
    """工具信息类"""
    
    def __init__(self,
                 name: str,
                 func: Callable,
                 description: str = "",
                 model: Optional[Type[BaseModel]] = None):
        self.name = name
        self.func = func
        self.description = description or func.__doc__ or ""
        self._params_model = model
        
        # 如果没有提供模型，自动生成
        if not model:
            self._generate_params_model()
            
    def _generate_params_model(self):
        """从函数签名生成参数模型"""
        sig = inspect.signature(self.func)
        type_hints = get_type_hints(self.func)
        
        # 收集字段定义
        fields = {}
        for name, param in sig.parameters.items():
            field_type = type_hints.get(name, Any)
            
            # 获取字段约束
            constraints = {}
            if hasattr(self.func, '__field_constraints__'):
                constraints = self.func.__field_constraints__.get(name, {})
                
            # 检查是否有Field标注
            if isinstance(param.default, FieldInfo):
                field_info = param.default
            else:
                field_info = field(
                    default=... if param.default is inspect.Parameter.empty else param.default,
                    **constraints
                )
                
            fields[name] = (field_type, field_info)
            
        # 创建模型类
        model_name = f"{self.name.title()}"
        self._params_model = create_model(
            model_name,
            **fields,
            __config__=type('Config', (), {'extra': 'forbid'})
        )
        
    def get_openai_schema(self) -> Dict:
        """转换为OpenAI函数调用schema"""
        return openai.pydantic_function_tool(
            model=self._params_model,
            description=self.description
        )
        
    def validate_and_call(self, **kwargs) -> Any:
        """验证参数并调用函数"""
        params = self._params_model(**kwargs)
        return self.func(**params.model_dump())

class McpToolset:
    """工具集类"""
    
    def __init__(self):
        self.tools: Dict[str, ToolInfo] = {}
        
    def register_tool(self,
                     name: str = "",
                     description: str = "",
                     model: Optional[Type[BaseModel]] = None) -> Callable:
        """
        工具注册装饰器
        Args:
            name: 工具名称（可选，默认使用函数名）
            description: 工具描述
            model: 参数模型类（可选，默认从函数签名生成）
        """
        def decorator(func: Callable) -> Callable:
            @wraps(func)
            def wrapper(*args, **kwargs) -> Any:
                return func(*args, **kwargs)
                
            tool_name = name or func.__name__
            if tool_name in self.tools:
                raise ValueError(f"Tool '{tool_name}' already registered")
                
            self.tools[tool_name] = ToolInfo(
                name=tool_name,
                func=wrapper,
                description=description,
                model=model
            )
            return wrapper
        return decorator
        
    def get_tool(self, name: str) -> Optional[ToolInfo]:
        """获取指定名称的工具"""
        return self.tools.get(name)
        
    def tool_exists(self, name: str) -> bool:
        """检查工具是否存在"""
        return name in self.tools
        
    def tool_use(self, __name: str, **kwargs) -> Any:
        """
        执行工具调用
        Args:
            name: 工具名称
            **kwargs: 工具参数
        Returns:
            工具执行结果
        """
        if not self.tool_exists(__name):
            raise ValueError(f"Tool '{__name}' not found")
            
        tool = self.get_tool(__name)
        try:
            return tool.validate_and_call(**kwargs)
        except Exception as e:
            raise ValueError(f"Error executing tool '{__name}': {str(e)}")
            
    def get_schemas(self) -> List[Dict]:
        """获取所有工具的OpenAI schema"""
        return [tool.get_openai_schema() for tool in self.tools.values()]
        
    def list_tools(self) -> List[str]:
        """获取所有工具名称列表"""
        return list(self.tools.keys())
        
    def clear_tools(self) -> None:
        """清除所有注册的工具"""
        self.tools.clear()
